package com.file.parser.socialsecurity;

import com.file.bo.ResponseData;
import com.file.bo.socialsecurity.BeijingIndividualRecordSheet;
import com.file.bo.socialsecurity.BeijingInsuranceParticipation;
import com.file.constant.ErrorCode;
import com.file.parser.BasePdfParser;
import com.file.util.JsonUtils;
import com.google.common.base.Splitter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.SpreadsheetDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 全国电子社保北京市社会参保证明&社会保险权益个人记录pdf解析
 * @author anyspa
 */

@Slf4j
public class BeijingSocialSecurityPdfParser extends BasePdfParser {
    public ResponseData<String> parseBeijingSocialSecurityPdfToJson(String daId, String filePath) {
        log.info("parseBeijingSocialSecurityPdfToJson started, daId:{}", daId);
        String json = null;

        try {
            if (filePath.contains("cbzm")) {
                BeijingInsuranceParticipation beijingInsuranceParticipation = parseBeijingInsuranceParticipation(filePath);
                json = JsonUtils.convertObjectToJson(beijingInsuranceParticipation);
            } else if (filePath.contains("qyd")) {
                BeijingIndividualRecordSheet beijingIndividualRecordSheet = parseBeijingIndividualRecordSheet(filePath);
                json = JsonUtils.convertObjectToJson(beijingIndividualRecordSheet);
            } else {
                log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseBeijingSocialSecurityPdfToJson failed, new type not supported");
                return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
            }
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseBeijingSocialSecurityPdfToJson failed", e);
            return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseBeijingSocialSecurityPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private BeijingIndividualRecordSheet parseBeijingIndividualRecordSheet(String filePath) {
        BeijingIndividualRecordSheet beijingIndividualRecordSheet = parseBeijingIndividualRecordSheetHeader(filePath);
        List<List<String>> rowList = parseFileToRowList(filePath);
//        for (List<String> cellList : rowList) {
//            System.out.println(cellList);
//        }

        parseListToBO(rowList, beijingIndividualRecordSheet);
        return beijingIndividualRecordSheet;
    }

    private BeijingIndividualRecordSheet parseBeijingIndividualRecordSheetHeader(String filePath) {
        BeijingIndividualRecordSheet beijingIndividualRecordSheet = new BeijingIndividualRecordSheet();
        String pdfHeaderText = getPdfTextByStripper2(filePath);
        pdfHeaderText = pdfHeaderText.replace(System.getProperty("line.separator", "\n"), "");
        String name = pdfHeaderText.substring(pdfHeaderText.indexOf("姓名：") + 3, pdfHeaderText.indexOf("电脑序号")).trim();
        String computerSerialNo = pdfHeaderText.substring(pdfHeaderText.indexOf("电脑序号：") + 5, pdfHeaderText.indexOf("社会保障号码")).trim();
        String socialInsuranceNo = pdfHeaderText.substring(pdfHeaderText.indexOf("社会保障号码：") + 7, pdfHeaderText.indexOf("人员类别")).trim();
        String personalCategory = pdfHeaderText.substring(pdfHeaderText.indexOf("人员类别：") + 5, pdfHeaderText.indexOf("单位")).trim();
        String unit = pdfHeaderText.substring(pdfHeaderText.indexOf("单位：") + 3, pdfHeaderText.indexOf("工伤保险")).trim();
        String comment = pdfHeaderText.substring(pdfHeaderText.indexOf("说明：") + 3, pdfHeaderText.indexOf("查询网址")).trim();

        String pensionActualPaymentUntilKey = "";
        Pattern pattern = Pattern.compile("至\\d{4}年末养老累计实际缴费年限");
        Matcher matcher = pattern.matcher(pdfHeaderText);
        if (matcher.find()) {
            pensionActualPaymentUntilKey = matcher.group().concat("(仅限本市)");
            beijingIndividualRecordSheet.setYear(pensionActualPaymentUntilKey.substring(1, 5));
        }

        String queryURL = pdfHeaderText.substring(pdfHeaderText.indexOf("查询网址：") + 5, pdfHeaderText.indexOf("打印日期")).trim();
        if (StringUtils.contains(queryURL, "  ")) {//NOSONAR
            queryURL = queryURL.replaceAll("  ", "");//NOSONAR
        }
        String printingDate = pdfHeaderText.substring(pdfHeaderText.indexOf("打印日期：") + 5).trim();
        if (StringUtils.contains(printingDate, StringUtils.SPACE)) {
            printingDate = printingDate.replaceAll("\\s+", "");
        }

        beijingIndividualRecordSheet.setName(name);
        beijingIndividualRecordSheet.setComputerSerialNo(computerSerialNo);
        beijingIndividualRecordSheet.setSocialInsuranceNo(socialInsuranceNo);
        beijingIndividualRecordSheet.setPersonalCategory(personalCategory);
        beijingIndividualRecordSheet.setUnit(unit);

        String text = pdfHeaderText.substring(pdfHeaderText.indexOf("(仅限本市)(仅限本市)") + 12,
                pdfHeaderText.indexOf("说明：")).trim();
        List<String> textList = Splitter.on(StringUtils.SPACE).splitToList(text);
        if (textList.size() != 6) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), "", "", "", "Beijing individualRecordSheet Pdf format changed");
            throw new RuntimeException();
        }

        beijingIndividualRecordSheet.setPensionPersonalAccountPreviousYearTotal(textList.get(0));
        beijingIndividualRecordSheet.setPensionPersonalAccountThisYearTotal(textList.get(1));
        beijingIndividualRecordSheet.setPensionRepayThisYearTotal(textList.get(2));
        beijingIndividualRecordSheet.setCurrentYearInterest(textList.get(3));
        beijingIndividualRecordSheet.setPensionPersonalAccountTotal(textList.get(4));
        beijingIndividualRecordSheet.setData(pensionActualPaymentUntilKey, textList.get(5));
        beijingIndividualRecordSheet.setData("说明", comment);
        beijingIndividualRecordSheet.setData("查询网址", queryURL);
        beijingIndividualRecordSheet.setData("打印日期", printingDate);

        return beijingIndividualRecordSheet;
    }

    private BeijingInsuranceParticipation parseBeijingInsuranceParticipation(String filePath) {
        BeijingInsuranceParticipation beijingInsuranceParticipation = parseBeijingInsuranceParticipationHeader(filePath);
        List<List<String>> rowList = parseFileToRowList(filePath);
//        for (List<String> cellList : rowList) {
//            System.out.println(cellList);
//        }
        parseListToBO(rowList, beijingInsuranceParticipation);

        return beijingInsuranceParticipation;
    }

    private void parseListToBO(List<List<String>> rowList, BeijingInsuranceParticipation beijingInsuranceParticipation) {
        List<BeijingInsuranceParticipation.PensionUnitChangeRecord> pensionUnitChangeRecords = new ArrayList<>();
        List<BeijingInsuranceParticipation.SocialInsurancePaymentTran> socialInsurancePaymentTrans = new ArrayList<>();
        beijingInsuranceParticipation.setPensionUnitChangeRecords(pensionUnitChangeRecords);
        beijingInsuranceParticipation.setSocialInsurancePaymentTrans(socialInsurancePaymentTrans);

        String sectionName = "";

        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equals(cellList.get(1), "缴费截止年月")) {
                sectionName = "养老保险单位变动记录";
                continue;
            } else if (cellList.get(0).contains("五险缴费明细") || StringUtils.equals(cellList.get(0), "月数")) {
                continue;
            } else if (StringUtils.equalsAny(cellList.get(2), "养老实际缴", "年缴费基数")) {
                sectionName = "五险缴费明细";
                continue;
            }
            switch (sectionName) { //NOSONAR
                case "养老保险单位变动记录":
                    BeijingInsuranceParticipation.PensionUnitChangeRecord pensionUnitChangeRecord = new BeijingInsuranceParticipation.PensionUnitChangeRecord();
                    pensionUnitChangeRecord.setPaymentStartDate(cellList.get(0));
                    pensionUnitChangeRecord.setPaymentEndDate(cellList.get(1));
                    pensionUnitChangeRecord.setActualPaymentMonths(cellList.get(2));
                    pensionUnitChangeRecord.setCompanyName(cellList.get(3));
                    pensionUnitChangeRecord.setPaymentDistrict(cellList.get(4));
                    pensionUnitChangeRecords.add(pensionUnitChangeRecord);
                    break;
                case "五险缴费明细":
                    BeijingInsuranceParticipation.SocialInsurancePaymentTran socialInsurancePaymentTran = new BeijingInsuranceParticipation.SocialInsurancePaymentTran();
                    socialInsurancePaymentTran.setPaymentStartAndEndDate(cellList.get(0));

                    BeijingInsuranceParticipation.PensionActualPayment pensionActualPayment = new BeijingInsuranceParticipation.PensionActualPayment();
                    pensionActualPayment.setMonth(cellList.get(1));
                    pensionActualPayment.setAnnualPaymentBase(cellList.get(2));
                    pensionActualPayment.setPersonalPayment(cellList.get(3));
                    socialInsurancePaymentTran.setPensionActualPayment(pensionActualPayment);

                    BeijingInsuranceParticipation.UnemploymentActualPayment unemploymentActualPayment = new BeijingInsuranceParticipation.UnemploymentActualPayment();
                    unemploymentActualPayment.setMonth(cellList.get(4));
                    unemploymentActualPayment.setAnnualPaymentBase(cellList.get(5));
                    unemploymentActualPayment.setPersonalPayment(cellList.get(6));
                    socialInsurancePaymentTran.setUnemploymentActualPayment(unemploymentActualPayment);

                    BeijingInsuranceParticipation.InjuryActualPayment injuryActualPayment = new BeijingInsuranceParticipation.InjuryActualPayment();
                    injuryActualPayment.setMonth(cellList.get(7));
                    injuryActualPayment.setAnnualPaymentBase(cellList.get(8));
                    socialInsurancePaymentTran.setInjuryActualPayment(injuryActualPayment);

                    BeijingInsuranceParticipation.MedicalActualPayment medicalActualPayment = new BeijingInsuranceParticipation.MedicalActualPayment();
                    medicalActualPayment.setMonth(cellList.get(9));
                    medicalActualPayment.setAnnualPaymentBase(cellList.get(10));
                    medicalActualPayment.setPersonalPayment(cellList.get(11));
                    socialInsurancePaymentTran.setMedicalActualPayment(medicalActualPayment);

                    BeijingInsuranceParticipation.FertilityActualPayment fertilityActualPayment = new BeijingInsuranceParticipation.FertilityActualPayment();
                    fertilityActualPayment.setMonth(cellList.get(12));
                    fertilityActualPayment.setAnnualPaymentBase(cellList.get(13));
                    socialInsurancePaymentTran.setFertilityActualPayment(fertilityActualPayment);

                    socialInsurancePaymentTrans.add(socialInsurancePaymentTran);

                    break;
            }
        }
    }

    private void parseListToBO(List<List<String>> rowList, BeijingIndividualRecordSheet beijingIndividualRecordSheet) {
        List<BeijingIndividualRecordSheet.PaymentRecord> paymentRecords = new ArrayList<>();
        beijingIndividualRecordSheet.setPaymentRecords(paymentRecords);

        String sectionName = "";

        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equalsAny(cellList.get(2), "养老保险缴费信息", "月缴费基数", "单位缴费")) {
                sectionName = "月缴费记录";
                continue;
            } else if (StringUtils.isEmpty(cellList.get(0)) && StringUtils.isEmpty(cellList.get(1))) {
                break;
            }
            switch (sectionName) { //NOSONAR
                case "月缴费记录":
                    BeijingIndividualRecordSheet.PaymentRecord paymentRecord = new BeijingIndividualRecordSheet.PaymentRecord();
                    String year = beijingIndividualRecordSheet.getYear();
                    String month = cellList.get(0).length() == 1 ? "0" + cellList.get(0) : cellList.get(0);
                    paymentRecord.setYearAndMonth(year + "/" + month);
                    paymentRecord.setDeclaredMonthlySalary(cellList.get(1));

                    BeijingIndividualRecordSheet.PensionPaymentInfo pensionPaymentInfo = new BeijingIndividualRecordSheet.PensionPaymentInfo();
                    pensionPaymentInfo.setPaymentBase(cellList.get(2));
                    pensionPaymentInfo.setUnitPayment(cellList.get(3));
                    pensionPaymentInfo.setPersonalPayment(cellList.get(4));
                    paymentRecord.setPensionPaymentInfo(pensionPaymentInfo);

                    BeijingIndividualRecordSheet.UnemploymentInsurancePaymentInfo unemploymentInsurancePaymentInfo = new BeijingIndividualRecordSheet.UnemploymentInsurancePaymentInfo();
                    unemploymentInsurancePaymentInfo.setPaymentBase(cellList.get(5));
                    unemploymentInsurancePaymentInfo.setUnitPayment(cellList.get(6));
                    unemploymentInsurancePaymentInfo.setPersonalPayment(cellList.get(7));
                    paymentRecord.setUnemploymentInsurancePaymentInfo(unemploymentInsurancePaymentInfo);

                    BeijingIndividualRecordSheet.InjuryInsurancePaymentInfo injuryInsurancePaymentInfo = new BeijingIndividualRecordSheet.InjuryInsurancePaymentInfo();
                    injuryInsurancePaymentInfo.setPaymentBase(cellList.get(8));
                    injuryInsurancePaymentInfo.setUnitPayment(cellList.get(9));
                    paymentRecord.setInjuryInsurancePaymentInfo(injuryInsurancePaymentInfo);

                    BeijingIndividualRecordSheet.MedicalInsurancePaymentInfo medicalInsurancePaymentInfo = new BeijingIndividualRecordSheet.MedicalInsurancePaymentInfo();
                    medicalInsurancePaymentInfo.setPaymentBase(cellList.get(10));
                    medicalInsurancePaymentInfo.setUnitPayment(cellList.get(11));
                    medicalInsurancePaymentInfo.setPersonalPayment(cellList.get(12));
                    paymentRecord.setMedicalInsurancePaymentInfo(medicalInsurancePaymentInfo);

                    paymentRecords.add(paymentRecord);
                    break;
            }
        }
    }

    private BeijingInsuranceParticipation parseBeijingInsuranceParticipationHeader(String filePath) {
        BeijingInsuranceParticipation beijingInsuranceParticipation = new BeijingInsuranceParticipation();
        String pdfHeaderText = getPdfTextByStripper2(filePath).replace(System.getProperty("line.separator", "\n"), "");;

        String name = pdfHeaderText.substring(pdfHeaderText.indexOf("参保人姓名:") + 6, pdfHeaderText.indexOf("校验码:")).trim();
        String verifyCode = pdfHeaderText.substring(pdfHeaderText.indexOf("校验码:") + 4, pdfHeaderText.indexOf("社会保障号码:")).trim();
        String socialInsuranceNo = pdfHeaderText.substring(pdfHeaderText.indexOf("社会保障号码:") + 7, pdfHeaderText.indexOf("查询流水号:")).trim();
        String queryFlowingNo = pdfHeaderText.substring(pdfHeaderText.indexOf("查询流水号:") + 6, pdfHeaderText.indexOf("单位名称:")).trim();
        String companyName = pdfHeaderText.substring(pdfHeaderText.indexOf("单位名称:") + 5, pdfHeaderText.indexOf("查询日期:")).trim();
        String queryDate = pdfHeaderText.substring(pdfHeaderText.indexOf("查询日期:") + 5, pdfHeaderText.indexOf("一、养老保险单位变动记录")).trim();

        String pensionActualTotalPaymentYears = pdfHeaderText.substring(pdfHeaderText.indexOf("参保人在我市养老保险累计实际缴费年限") + 18,
                pdfHeaderText.indexOf("(其中")).trim();
        String medicalActualTotalPaymentYears = pdfHeaderText.substring(pdfHeaderText.indexOf("医疗保险累计实际缴费年限") + 12,
                pdfHeaderText.indexOf("截至")).trim();
        if (medicalActualTotalPaymentYears.contains("。")) {
            medicalActualTotalPaymentYears = medicalActualTotalPaymentYears.substring(0, medicalActualTotalPaymentYears.indexOf("。"));
        }
        String pensionPersonalAccountBalance = pdfHeaderText.substring(pdfHeaderText.indexOf("养老保险个人账户本息合计金额：") + 15,
                pdfHeaderText.indexOf("元。")).trim();

        beijingInsuranceParticipation.setName(name);
        beijingInsuranceParticipation.setVerifyCode(verifyCode);
        beijingInsuranceParticipation.setSocialInsuranceNo(socialInsuranceNo);
        beijingInsuranceParticipation.setQueryFlowingNo(queryFlowingNo);
        beijingInsuranceParticipation.setCompanyName(companyName);
        beijingInsuranceParticipation.setQueryDate(queryDate);
        beijingInsuranceParticipation.setPensionActualTotalPaymentYears(pensionActualTotalPaymentYears.replaceAll("\\s+", ""));
        beijingInsuranceParticipation.setMedicalActualTotalPaymentYears(medicalActualTotalPaymentYears.replaceAll("\\s+", ""));
        beijingInsuranceParticipation.setPensionPersonalAccountBalance(pensionPersonalAccountBalance);
        return beijingInsuranceParticipation;
    }





    private List<List<String>> parseFileToRowList(String filePath) {
        // 1. 读取文件
        File pdf = new File(filePath);

        //页面所有table的记录，每一个元素代表下面一条记录cellList
        List<List<String>> rowList = new ArrayList<>();

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {
            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            SpreadsheetDetectionAlgorithm detectionAlgorithm = new SpreadsheetDetectionAlgorithm();
            Map<Integer, List<Rectangle>> pageNumber2RectangleListMap = new HashMap<>();//key为页的序号， value为对应的Rectangle的list

            // 4. 获取每页的PageIterator
            PageIterator pageIterator = objectExtractor.extract();

            // 5. 解析每页的Rectangle
            // 如果单页pdf中有多个Rectangle，则解析出来的List<Rectangle>会有多个对象
            while (pageIterator.hasNext()) {
                Page page = pageIterator.next();
                List<Rectangle> rectangleList = detectionAlgorithm.detect(page);
                if (rectangleList.size() > 0) {
                    pageNumber2RectangleListMap.put(page.getPageNumber(), rectangleList);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm extractionAlgorithm = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : pageNumber2RectangleListMap.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());
                Rectangle rectangle = null;

                List<Rectangle> rectangleList = entry.getValue();
                for (Rectangle r : rectangleList) {
                    double rectangleHeight = r.getHeight();
                    if (Double.compare(rectangleHeight, 0) > 0) {
                        rectangle = r;
                        break;
                    }
                }
                if (rectangle == null) {
                    throw new RuntimeException("rectangle is null.");
                }

                if (entry.getKey() > 1) {
                    rectangle.setTop(rectangle.getTop());
                }
                rectangle.setBottom(rectangle.getBottom() + 500);
                Page area = page.getArea(rectangle);

                // 如果每页有多个表格，解析每一个table
                List<Table> tableList = extractionAlgorithm.extract(area);
                for (Table table : tableList) {
                    for (int i = 0; i < table.getRowCount(); i++) {
                        List<String> cellList = new ArrayList<>();//一条记录，每个单元格占一个元素
                        for (int j = 0; j < table.getColCount(); j++) {
                            cellList.add(table.getCell(i, j).getText(false));
                        }
                        rowList.add(cellList);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

        return rowList;
    }

    public static void main(String[] args) {
        BeijingSocialSecurityPdfParser beijingSocialSecurityPdfParser = new BeijingSocialSecurityPdfParser();
        String json = "";

        // 参保证明
        json = beijingSocialSecurityPdfParser.parseBeijingSocialSecurityPdfToJson("", "D:\\data\\file\\socialsecurity\\北京\\20240619\\zd49v0vo1802902690894012416_82ef6152cd27a2e5680d01aa3595214d_app-gjzwfw-dzsb_origins\\app-gjzwfw-dzsb_cbzm.pdf").getData();
        System.out.println(json);


        // 权益单
//        json = beijingSocialSecurityPdfParser.parseBeijingSocialSecurityPdfToJson("", "D:\\data\\file\\socialsecurity\\北京\\20240619\\zd47iaqw1802995195388932096_d5f64c8da055f442c289dfcb03a3fa4b_app-gjzwfw-dzsb_origins\\app-gjzwfw-dzsb_qyd.pdf").getData();
//        System.out.println(json);

    }
}
